package com.zlkj.pro.core.security;

import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi;
import cn.stylefeng.roses.kernel.auth.api.context.LoginUserHolder;
import cn.stylefeng.roses.kernel.auth.api.enums.DataScopeTypeEnum;
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import cn.stylefeng.roses.kernel.config.api.context.ConfigContext;
import cn.stylefeng.roses.kernel.jwt.api.pojo.payload.DefaultJwtPayload;
import cn.stylefeng.roses.kernel.jwt.factory.JwtTokenApiFactory;
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.ResourceDefinition;
import cn.stylefeng.roses.kernel.system.api.pojo.role.request.SysRoleRequest;
import cn.stylefeng.roses.kernel.system.api.pojo.user.SysUserDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.user.request.SysUserRequest;
import cn.stylefeng.roses.kernel.system.modular.role.service.SysRoleService;
import cn.stylefeng.roses.kernel.system.modular.role.service.impl.SysRoleServiceImpl;
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserService;
import com.zlkj.pro.core.consts.ProjectConstants;
import com.zlkj.pro.core.exception.BusinessException;
import com.zlkj.pro.core.exception.enums.BusinessExceptionEnum;
import com.zlkj.pro.core.security.base.BaseSecurityInterceptor;
import com.zlkj.pro.core.security.validate.ValidateTokenServiceApi;
import com.zlkj.pro.core.util.ConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Optional;

import static com.zlkj.pro.core.consts.ProjectConstants.VERSION_FOREIGN;
import static com.zlkj.pro.core.consts.ProjectConstants.VERSION_TYPE;
import static com.zlkj.pro.core.exception.enums.BusinessExceptionEnum.THE_CURRENT_ACCOUNT_IS_ALREADY_LOGGED_IN_ON_ANOTHER_DEVICE;

/**
 * 鉴权的过滤器，用来鉴权token
 *
 * @author fengshuonan
 * @date 2020/12/15 22:45
 */
@Component
@Slf4j
public class AuthJwtTokenSecurityInterceptor extends BaseSecurityInterceptor {

    /**
     * 登陆服务Api
     */
    @Autowired
    private AuthServiceApi authServiceApi;
    @Autowired
    private ValidateTokenServiceApi validateTokenServiceApi;
    @Autowired
    private CacheOperatorApi<String> cacheOperatorApi;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysRoleService sysRoleService;


    @Override
    public void filterAction(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, ResourceDefinition resourceDefinition, String token, Object handler) {
        // 1. 获取当前请求的路径
        String requestURI = httpServletRequest.getRequestURI();
        // 2. 如果需要登录
        if (resourceDefinition.getRequiredLoginFlag()) {
            // token为空，返回用户校验失败
            if (StrUtil.isEmpty(token)) {
                throw new AuthException(BusinessExceptionEnum.LOGIN_IS_INVALID_PLEASE_LOG_IN_AGAIN);
            }
            // 3.校验token和用户会话信息是否正确
            if (requestURI.contains(ProjectConstants.SERVICE_API_PREFIX)) {
                validateTokenServiceApi.checkAuth(token, requestURI);
                Long userId = loginUserHolder(token);
                //校验token是否需要重新登录
                String oldToken = cacheOperatorApi.get(String.format(ProjectConstants.USER_TOKEN, userId));
                if (StrUtil.isNotBlank(oldToken)) {
//                    throw new BusinessException(AUTH_EXPIRED_ERROR);
                    if (!oldToken.equals(token)) {
                        throw new BusinessException(THE_CURRENT_ACCOUNT_IS_ALREADY_LOGGED_IN_ON_ANOTHER_DEVICE);
                    }
                }
                String versionType = Optional.ofNullable(httpServletRequest.getHeader(VERSION_TYPE)).orElse("");
                if (!VERSION_FOREIGN.equals(versionType)) {
                    if (handler instanceof HandlerMethod) {
                        HandlerMethod methodObj = (HandlerMethod) handler;
                        Annotation[] annotations = methodObj.getMethod().getAnnotations();
                        for (Annotation annotation : annotations) {

                        }
                    }
                }
            } else {
                authServiceApi.checkAuth(token, requestURI);
            }
        } else {
            if (requestURI.contains(ProjectConstants.SERVICE_API_PREFIX)) {
                loginUserHolder(token);
            }
        }
    }

    private Long loginUserHolder(String token) {
        DefaultJwtPayload defaultPayload = new DefaultJwtPayload();
        try {
            String jwtSecret = ConfigContext.me().getConfigValueNullable("BUSINESS_API_JWT_SECRET", String.class);
            Integer jwtExpiredSeconds = ConfigContext.me().getConfigValueNullable("BUSINESS_API_JWT_EXPIRED_SECONDS", Integer.class);
            defaultPayload = JwtTokenApiFactory.createJwtApi(jwtSecret, jwtExpiredSeconds).getDefaultPayload(token);
        } catch (Exception ignored) {
        }
        Long userId = defaultPayload.getUserId();
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(userId);
        loginUser.setAccount(defaultPayload.getAccount());
        // 补全用户信息
        SysUserRequest userRequest = new SysUserRequest();
        userRequest.setUserId(userId);
        SysUserDTO userDto = sysUserService.detail(userRequest);
        loginUser.setSuperAdmin(userDto.getSuperAdminFlag().equals("Y"));
        loginUser.setDataScopeTypeEnums(Collections.singleton(DataScopeTypeEnum.ALL));
        LoginUserHolder.set(loginUser);
        return userId;
    }

}
